Golang : Derive cryptographic key from passwords with Argon2
Argon2 is a method used to derive cryptographic key from passwords which has a few advantages over the "traditional method" of key generation from passwords. To learn more about the Argon2 method and the advantage it offers, please see https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
Below is an example adapted from previous AES tutorial, but this time ... instead of hard coding the AES key, we will use Argon2 to generate the key from our password.
Here you go!
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"fmt"
"golang.org/x/crypto/argon2"
)
func main() {
passwd := []byte("password")
salt := randStr(32, "alphanum") // generate a 32 bytes of random alpha-numeric string
// read more the advantage of using Argon2 to derive cryptographic keys from password
//https://tip.golang.org/pkg/golang.org/x/crypto/argon2/
argon2key := argon2.IDKey(passwd, salt, 1, 64*1024, 4, 32)
fmt.Println("Salt : ", salt)
fmt.Println("Argon2 Key : ", argon2key)
fmt.Println("Size of argon2 key : ", len(argon2key))
// taken from https://socketloop.com/tutorials/golang-how-to-encrypt-with-aes-crypto
// instead of hardcoding our 32 bytes AES key, we now use the key from Argon2
block, err := aes.NewCipher([]byte(argon2key))
if err != nil {
panic(err)
}
fmt.Printf("%d bytes NewCipher key with block size of %d bytes\n", len(argon2key), block.BlockSize)
// 16 bytes for AES-128, 24 bytes for AES-192, 32 bytes for AES-256
ciphertext := []byte("abcdef1234567890ghijklmno98765432")
iv := ciphertext[:aes.BlockSize] // const BlockSize = 16, doesn't matter if AES-256 or AES-192... still use this constant
// verify
// fmt.Println(string(iv))
secret := []byte("Hello! 妳好嗎?")
// encrypt
encrypter := cipher.NewCFBEncrypter(block, iv)
encrypted := make([]byte, len(secret))
encrypter.XORKeyStream(encrypted, secret)
fmt.Printf("%s encrypted to %v\n", secret, encrypted)
// verify
//fmt.Printf("%s encrypted to %s\n", secret, string(encrypted))
// let's decrypt back and see how it goes
decrypter := cipher.NewCFBDecrypter(block, iv) // simple!
decrypted := make([]byte, len(encrypted))
decrypter.XORKeyStream(decrypted, encrypted)
fmt.Printf("%s decrypted to %s\n", string(encrypted), decrypted)
}
// MODIFIED from https://socketloop.com/tutorials/golang-how-to-generate-random-string
func randStr(strSize int, randType string) []byte {
var dictionary string
if randType == "alphanum" {
dictionary = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
}
if randType == "alpha" {
dictionary = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
}
if randType == "number" {
dictionary = "0123456789"
}
var bytes = make([]byte, strSize)
rand.Read(bytes)
for k, v := range bytes {
bytes[k] = dictionary[v%byte(len(dictionary))]
}
return bytes
}
Sample output:
Salt : [79 86 116 122 119 119 86 103 76 114 100 85 78 52 68 114 99 54 101 118 99 121 68 81 119 77 115 52 115 102 112 114]
Argon2 Key : [151 57 205 221 57 249 116 92 116 49 39 27 249 199 53 72 203 75 105 96 108 251 91 180 217 231 14 42 160 210 222 169]
Size of argon2 key : 32
32 bytes NewCipher key with block size of 4930928 bytes
Hello! 妳好嗎? encrypted to [19 124 253 101 212 157 235 168 47 158 7 27 145 220 53 5 74]
|�eԝ�/��5J decrypted to Hello! 妳好嗎?
Happy coding!
References:
https://github.com/P-H-C/phc-winner-argon2/blob/master/argon2-specs.pdf
https://socketloop.com/tutorials/golang-how-to-encrypt-with-aes-crypto
https://socketloop.com/tutorials/golang-how-to-generate-random-string
https://tip.golang.org/pkg/golang.org/x/crypto/argon2/
https://socketloop.com/tutorials/golang-automatically-figure-out-array-length-size-with-three-dots
See also : Golang : Encrypt and decrypt data with AES crypto
By Adam Ng(黃武俊)
IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.
Advertisement
Tutorials
+18.9k Golang : Get host name or domain name from IP address
+11.2k Swift : Convert (cast) Float to String
+21.3k Golang : Convert string slice to struct and access with reflect example
+31.8k Golang : Math pow(the power of x^y) example
+11.9k Golang : Simple client-server HMAC authentication without SSL example
+11.7k Golang : Sort and reverse sort a slice of runes
+11.7k Golang : Determine if time variables have same calendar day
+4.3k Javascript : Detect when console is activated and do something about it
+4.1k Javascript : How to show different content with noscript?
+10.6k Golang : How to transmit update file to client by HTTP request example
+4.9k Golang : Experimental Jawi programming language